#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include "List.h"

/*allways to chek if all not pointing to stubs with assert*/
/*to initial ptr to nul and optimizer will optimize it to the right value*/


typedef     struct  node_t
{
	void           *data;
	struct node_t  *next;
	struct node_t  *prev;
}Node;


struct      List_t
{
  struct    node_t head;
  struct    node_t tail;

};

/*
 *         Static functions
 */

static void ListDel(List* _list);

/*
 *         Imp
 */

List*       ListNew(void)
{
    List*   list=(List*)malloc(sizeof(List));

    if(!list)
    {
        return 0;
    }

    list->head.data=0;
    list->tail.data=0;
    list->head.next=&list->tail;
    list->head.prev=0;
    list->tail.prev=&list->head;
    list->tail.next=0;

    return list;
}

int         ListIsEmpty(List* _list)
{
    assert(_list);

    if(_list->tail.prev==&_list->head)
    {
        return 1;
    }

    return 0;
}

void        listDestroy(List* _list)
{
    ListDel(_list);
    free(_list);
    #ifdef _DEBUG
     _list=(List*)0xdeadbeef;
     #endif

}
ListIter    ListBegin(List* _list)
{
    assert(_list);

    return (ListIter)_list->head.next;
}

ListIter    ListEnd(List* _list)
{
    assert(_list);

    return (ListIter)&_list->tail;
}

int ListIterIsEqual(ListIter _it1, ListIter _it2)
{
    assert(_it1 && _it2);

    return (Node*)_it1 == (Node*)_it2;
}

void*       ListGetData(ListIter _iter)
{
    assert(_iter);
    /*to chek if it not stub with assert*/

    if(!_iter)
    {
        return 0;
    }

    return ((Node*)_iter)->data;
}

ListIter    ListInsert(List *_list,ListIter _iter,void* _data)
{
    Node*   node;

    assert(_list);
    assert(_iter);
    /*add that operator not equa to head not first element*/

    node=(Node*)malloc(sizeof(node));

    if (!node)
    {
        return ListEnd(_list);
    }

    node->data = _data;
    node->prev = ((Node*)_iter)->prev;
    node->next=(Node*)_iter;
    ((Node*)_iter)->prev->next=node;
    ((Node*)_iter)->prev=node;

    return (ListIter)node;
}

ListIter    ListRemove(List *_list,ListIter _iter)
{
    assert(_list);

    if(_iter==ListEnd(_list))
    {
        return ListEnd(_list);
    }

    ((Node*)_iter)->prev->next=((Node*)_iter)->next;
    ((Node*)_iter)->next->prev=((Node*)_iter)->prev;



    /*to add free to node that we are free*/

    return (ListIter)((Node*)_iter)->next;

}

size_t  ListCount(List* _list)
{
    Node*   node        ;
    size_t  count = 0   ;

    assert(_list);

    node = _list->head.next;
    while(node != &_list->tail)
    {
        ++count;
        node = node->next;
    }
    return count;
}

ListIter    ListIterNext(ListIter _iter)
{
    assert(_iter);

    return (ListIter)((Node*)_iter)->next;
}

ListIter    ListIterPrev(ListIter _iter)
{
    assert(_iter);

    return (ListIter)((Node*)_iter)->prev;
}

void        ListDel(List* _list)
{
    while (ListBegin(_list)!=ListEnd(_list))
    {
        free(((Node*)ListBegin(_list)));

        #ifdef _DEBUG
        ListBegin(_list)=(ListIter)0xdeadbeef;
        #endif

        ListRemove(_list,ListBegin(_list));
    }

}


#ifdef utestList
#define Is_success(err,str) if (err) {printf("\n success with ...%s test \n",str);}\
else{printf("\n fail with...%s  test",str);}
#define Fail_pattern(err,str) if (err) {printf("\n fail pattern is ...%s \n ",str); return 0;}
#include<string.h>

void        Regresion_test(void);
int         ListInsertTest(void);
int         ListDelTest();
int         ListGetDataTest(void);

int main()
{

    Regresion_test();

    return 0;
}

int     ListInsertTest(void)
{
    List*   list=ListNew();
    char    buf1[10]="boris";
    char    buf2[10]="noam";
    char    buf3[10]="meyir";

    ListInsert(list,ListBegin(list),buf1);
    Fail_pattern(strcmp(ListGetData(ListBegin(list)),buf1),"ListInsert");
    ListInsert(list,ListBegin(list),buf2);
    Fail_pattern(strcmp(ListGetData(ListBegin(list)),buf2),"ListInsert");
    ListInsert(list,ListBegin(list),buf3);
    Fail_pattern(strcmp(ListGetData(ListBegin(list)),buf3),"ListInsert");

    return 1;
}

int    ListDelTest()
{
    List*   list=ListNew();
    char    buf1[10]="boris";
    char    buf2[10]="noam";
    char    buf3[10]="meyir";

    ListInsert(list,ListBegin(list),buf1);
    ListInsert(list,ListBegin(list),buf2);
    ListInsert(list,ListBegin(list),buf3);

    ListDel(list);

    Fail_pattern(ListBegin(list)!=ListEnd(list),"didnt erase all elements");

    return 1;


}

int       ListGetDataTest(void)
{
    List*   list=ListNew();
/*
    char    buf1[10]="boris";
    char    buf2[10]="noam";
    char    buf3[10]="meyir";


*/

    ListGetData(ListBegin(list));
    return 1;
}
void    Regresion_test()
{
    Is_success(ListInsertTest(),    "ListInsert ListNew ListBegin ListGetData ");
    Is_success(ListDelTest(), "ListDel");
    Is_success(ListGetDataTest(),"list get data test");

}


#endif


